#include "equalizer.h"
#include <iostream>
#include <assert.h>

Equalizer::Equalizer(Video* video, Sound* sound)
: Effect(video, sound), spectrum(NULL), spectrum_values(0), hist_full(false)
{
	CreateHistory();
	this_hist = history;
}

// Complicated deleting of history dynamic linked list
Equalizer::~Equalizer()
{
	History* h_temp = history;
	Bar* b_temp = history->bars;
	
	while (history != NULL)
	{
		while (history->bars != NULL)
		{
			b_temp = history->bars;
			history->bars = history->bars->next;
			delete b_temp;
		}

		h_temp = history;
		history = history->next;
		delete h_temp;
	}
}

void Equalizer::Render()
{
	spectrum = GetSpectrum();
	spectrum_values = (int)MAXFREQ / (int)GetEntryHz();

	// Does every bar a little more transparent
	for (History* hist = history; hist != NULL; hist = hist->next)
	{
		for (Bar* bar = hist->bars; bar != NULL; bar = bar->next)
			bar->color.a -= HISTORY_SPEED;
	}

	// Updates, adds of rewrites history and bar lists
	AddHistory();
	if (this_hist->bars == NULL)
		AddBar(this_hist);
	else ChangeBar(this_hist);

	// Draw background
	video->DrawBackground(COLOR_BLACK);

	// Draws history list
	DrawHistory(history);
}

// Add a new into hist element on the history list
void Equalizer::AddBar(Equalizer::History* hist)
{
	Bar* bar = NULL;

	for (int i = 0; i < spectrum_values; i++)
	{
		Bar* temp = new Bar;
		temp->id = i;
		temp->color = NoteColor(GetNote());
		temp->length = spectrum[i] * 5.0f;
		temp->next = NULL;

		if (hist->bars == NULL)
		{
			hist->bars = temp;
			bar = hist->bars;
			continue;
		}
		bar->next = temp;
		bar = bar->next;
	}
}

// Adds new history element to list, goes to the next element if it is full
void Equalizer::AddHistory()
{
	History* temp = NULL;

	if (hist_full)
	{
		if (this_hist->next == NULL)
			this_hist = history;
		else this_hist = this_hist->next;
		return;
	}

	temp = new History;
	temp->id = this_hist->id + 1;
	temp->bars = NULL;
	temp->next = NULL;

	this_hist->next = temp;
	this_hist = this_hist->next;

	if (this_hist->id >= HISTORY_LEN)
		hist_full = true;
}

// Rewrites bar list data if it exist in hist element
void Equalizer::ChangeBar(Equalizer::History* hist)
{
	Bar* bar = hist->bars;
	assert(hist->bars != NULL);

	for (int i = 0; i < spectrum_values; i++)
	{
		bar->length = spectrum[i] * 5.0f;
		bar->color = NoteColor(GetNote());
		assert(bar->id == i);
		bar = bar->next;
	}
}

// Creates first element in history array
void Equalizer::CreateHistory()
{
	history = new History;
	history->bars = NULL;
	history->id = 0;
	history->next = NULL;
}

// Draw all sequence of bars, existing in list
void Equalizer::DrawBar(Equalizer::Bar* bar)
{
	Vector2 start(0.0f, 0.0f), end(0.0f, 0.0f);
	float x_pos;

	for (Bar* _bar = bar; _bar != NULL; _bar = _bar->next)
	{
		x_pos = (float)_bar->id / (float)spectrum_values * 2.0f - 1.0f;
		start.x = x_pos;
		start.y = -1.0f;
		end.x = x_pos;
		end.y = _bar->length - 1.0f;

		video->DrawLine(start, end, _bar->color);
	}
}

// Draw history list
void Equalizer::DrawHistory(Equalizer::History *hist)
{
	for (History* h = hist; h != NULL; h = h->next)
	{
		DrawBar(h->bars);
	}
}
